#coding=cp936

import win32api,win32com,win32file,pywintypes
from win32con import *
import os,time,threading

__doc__ = '''
       Functions&Interfaces for watching filesystem and creating file list.
       Author:Zheng QingChuan <zqc53@126.com>
       LastUpdate: 2007-4-2 4:51:41
    '''

#consts that missing from win32con
FILE_LIST_DIRECTORY = 0x0001
FILE_NOTIFY_CHANGE_CREATION = 0x00000040

Actions = {
   1:'CREATE',
   2:'DELETE',
   3:'FILE_UPDATE',
   4:'DIR_OR_FILE_NAME_UPDATE'
}

#pattern of file change notifition callback
def __onfilechangedcallback(action,filename):pass

#worker thread
class Worker(threading.Thread):
    dirName = 'c:\\'
    
#core method of dir watching 
def watch_dir_1(dirName = "c:\\",subtree=False,onfilechanged=__onfilechangedcallback):   
        try:
          hdir = win32file.CreateFile(
            dirName,
            FILE_LIST_DIRECTORY,
            FILE_SHARE_READ|FILE_SHARE_WRITE,
            None,
            OPEN_EXISTING,
            FILE_FLAG_BACKUP_SEMANTICS,
            0
            )
        except Exception:
          print '!Failed to watch',dirName
          #kill thread
          return
        while(1):
            time.sleep(3)  
            change = win32file.ReadDirectoryChangesW(
                hdir,
                1024,
                subtree,
                FILE_NOTIFY_CHANGE_LAST_WRITE|FILE_NOTIFY_CHANGE_DIR_NAME
                |FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_CREATION,
                None,
                None
                )
            try:
             #call callback method to implement further functions
             if onfilechanged == None:
                print str(change[0][0])+'>(%s)'%(Actions[change[0][0]]),dirName+change[0][1]
             else :
                onfilechanged(change[0][0],dirName+'\\'+change[0][1])
            except IndexError,ir:
                pass

#main method
def watch_dir(dirName,subtree=False,callback=None):
  watch_worker = Worker()
  watch_dir_1.func_defaults=(dirName,subtree,callback)
  watch_worker.run = watch_dir_1
  watch_worker.start()

#a progress-watching object
class progres_listener:
  bfinish = False
  def finish(self):
    self.bfinish = True
  def has_finished(self):
    return self.bfinish
  def report(self,**kw):
    '''report callback, should be implemented'''
    pass

#get all subdirs in a special dir  
def get_subtrees(root_dir='c:\\',sleep_time=.2,a_progres_obj=None):
  dirs = []
  counter = 0
  for root, dir, files in os.walk(root_dir):
    time.sleep(sleep_time)  
    #add dirs to list  
    for d in dir:
      counter += 1
      absdir = '\\'.join((root,d))
      dirs.append(absdir)
      #report progress
      if a_progres_obj != None:
        a_progres_obj.report(current_dir=absdir,total_dirs=counter)        
  a_progres_obj.finish()      
  return dirs

#multiple-thread version of get all subdirs in a special dir
def get_subtrees_t(root_dir,sleep_time=.2,a_progres_obj=None):
   gw = Worker()
   get_subtrees.func_defaults = (root_dir,sleep_time,a_progres_obj)
   gw.run = getSubtrees
   gw.start()

#a list of all drives   
def get_system_drivers():
    from win32com.client import Dispatch
    fso = Dispatch('scripting.filesystemobject')
    drvlist = map(lambda a:str(a)+'\\',fso.Drives)
    return drvlist    

def watch_all_drivers(callback=None):
  drivers = get_system_drivers()
  for drv in drivers:
    try:
     watch_dir(drv,True,callback and callback or None)
     time.sleep(.5)
    except error:
      #maybe a cd-rom or other non-local driver
      print "Error accours during watching %s, maybe a cd-rom or other non-local driver" % (drv,)
      pass


def watch_dirs(dirs,callback=None):
  for drv in dirs:
    try:
      print 'Watching:',drv
      watch_dir(drv,True,callback)   
      time.sleep(.5)
    except error:
       #maybe a cd-rom or other non-local driver
       print "Error accours during watching %s, maybe a cd-rom or other non-local driver" % (drv,)
       pass    

#main entry
if __name__ == '__main__':
  #report the indexing progress
  #def b_report(**kw):
  #  print kw['current_dir'],' total',kw['total_dirs']
  #  
  #po = progres_listener()
  #po.report = b_report
  #dirs = get_subtrees_t('d:\\bak\\Apache Group',.05,po)
  #while(po.has_finished() == False):
  #  time.sleep(.2)
  
  #main test of the module  
  watch_all_drivers(callback=None)
  time.sleep(500)

  

       